-
Notifications
You must be signed in to change notification settings - Fork 28
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Policy Expressions, takes 2 and 3 #144
base: master
Are you sure you want to change the base?
Conversation
Good suggestion by Erik Larsson.
Thiis is needed for non-secure boot use cases where we're using attestation to bootstrap trust.
5091162
to
6f38748
Compare
Ok! I've a trivial test script to demo |
6f38748
to
7f39ee8
Compare
I've also added long options for bash scripts. I should probably separate Also, I should make a |
7f39ee8
to
d70820b
Compare
So, I have explored enough that I can write a jq+bash+tpm2-tools thing now. A policy consists of: a) parameters, b) some (possibly none) bindings for those parameters, possibly referenced by URI, or possibly to be prompted for, c) the actual policy commands. Because one might want to create a policy as just a reference to another but with some parameters bound, a policy should itself be possible to refer to either by value or by URI, and, really, any subset of the policy should be possible to express either directly or by reference. So we're looking at something like: {
"name":"...",
"params":[...],
"bindings":[...],
"policy":"<URI>"
} or {
"name":"...",
"params":[...],
"bindings":[...],
"policy":[...]
} Each policy command would be either a string containing a URI or an object naming the policy command and its command parameters, and each command parameter could be inlined or a reference to a parameter to the policy, or -in the case of Each parameter would be an object with a name and a type, and possibly some default content. Each binding would be an object with a name of a parameter and contents for it. Parameter types would include:
Perhaps a parameter could specify some default content but not all (e.g., hash and signature algorithms, but not signatures, naturally), so that a binding need only provide the missing parts. References to parameters would become appropriate values of the appropriate types in the actual policy commands. E.g., object contexts might get loaded and referred to by handle, tickets might be passed in by value, etc.
Perhaps a policy could refer to or include another and specify alternatives for There would be two evaluation modes: trial (to compute a |
Parameters have to go with the policy definitions. Default bindings can too. External bindings would be provided by other policies or command-line arguments. Internal parameters would be a thing (tickets, for example, things output by TPM commands internal to the policy that are needed by other commands). So maybe something more like: {
"name":"...",
"bindings":[...],
"policy": "<URI>"
} or {
"name":"...",
"bindings":[...],
"policy": {
"parameters":[...],
"policyDef":[...]
} A {
"command":"policyX",
"cp<Name>":"<value> or else an object with a param reference",
"...":"...",
"rp<Name>":{"name":"<internal-param-name>","display":true},
"...":...
} A parameter reference would be: { "name":"<parameter-name>", "sub":"<sub-name>" } where Policy holes ( A parameter needs:
We might want to make things like hash and signature algorithms ancillary properties of a parameter naming a key, or we might want to make them separate parameters. I think the former. {
"name":"...",
"internal":false,
"type":"TPM2B_PUBLIC",
"default":"<base64-encoded>"
} A binding might be a prompt for a value or an actual value. If the parameter is something like a cryptographic key, then the value might be multipart (one part might be the key, another might be the various associated algorithms). |
I'm also thinking that this rbash prototype may be good enough for now because it's... simple and easy. |
I've pushed a WIP of take 3, this time using JSON and jq, all inspired by take 2. |
https://trustedcomputinggroup.org/wp-content/uploads/TSS_JSON_Policy_v0p7_r08_pub.pdf The code in take 3 is not implementing that. |
4705847
to
0eacd9c
Compare
We should be able to consume PEM and not have to convert it to TPM2B_PUBLIC. However, the tpm2-tools {tpm2 makecredential} and {tpm2 duplicate} commands can't handle that, and we use those in sbin/tpm2-send. For now we start an SW TPM per-invocation, and tear it down when exiting.
0eacd9c
to
ea5137a
Compare
ea5137a
to
bfa086a
Compare
bfa086a
to
4938776
Compare
29ec869
to
dd6d12f
Compare
dd6d12f
to
9163920
Compare
WIP WIP WIP -- not tested Let's try a different approach to expressing complex policies: - Policies as restricted bash scripts that can do very little besides evaluate TPM policies, and which are invoked via... - ...a driver script, `sbin/tpm2-policy`, that sets up the environment for running the policy, and takes optional additional artifacts to make available to the policy. - Constant artifacts would be things like: - signer keys for `policysigned` and `policyauthorize` - signer key names for `policyticket` and such - anything else you can imagine Non-constant artifacts would be things like: - saved object context files for signer keys for `policysigned` and `policyauthorize` - tickets from `verifysignature`, `policysecret`, and `policysigned` - timeout files - anything else you can imagine all of which can be written only in `.` / `$PWD`. - The policy scripts would run in the following environment: - a temp dir as the current directory, with `$TMPDIR` set to `$PWD` and in which all the necessary artifacts, including the policy script itself, shall have been placed - various TPM2_POLICY... env vars, mainly TPM2_POLICY_SESSION - `$PATH` set to have just two paths: an `rbin` (see below), and the `$PWD`/`$TMPDIR` itself into which the policy script will have been copied (this will allow the policy script to implement different sub-policies selected by its arguments by executing itself, possibly through the `rbin/policyor` wrapper). - The "rbin" directory in the PATH for the execution of policy scripts, with: - wrappers for all the tpm2_policy... commands - the wrapper for tpm2_policyor is a bit special, naturally - wrappers for tpm2_loadexternal and tpm2_verifysignature, and possibly others - links to or wrappers of a handful of useful system commands like `sha256sum`, `xxd`, `dc`, `bc`, `jq`, etc. - a wrapper around `xxd` and `cat` for creating files from stdin so that artifacts can be embedded as here documents in the script This way policies get all the expressive power of bash, and access to all the functionality of tpm2-tools' policy commands. TBD: - Test, debug, test, ... - Add rbin wrappers for importing duplicated keys (so they can provide authValues discretely!). - Maybe allow execution of `sbin/tpm2-recv` by linking it from the rbin? - Add sample policies that are interesting, like using a combination of `policysigned` and `policyauthorize` and `curl` (outside the policy script) to execute an external script that varies at runtime, or policies that use different passwords for N different users, or which use `policysigned` to let some other entity authenticate N different users (using `policyRef` to name them, say), policies requiring golden PCRs OR external policy, etc. Showcase `policyor`! It'd be very nice to be able to have a policy like this: (golden PCRs && user authValue) || (admin authValue OTP && NV revocation of OTP index) || (superadmin authValue) || ($policy_containing_policy_signed && policyauthorize_of_it) Perhaps with multiple superadmin authValues via `policyor`. Such a policy would allow a laptop to boot normally with a user password, and after emergency updates boot with an admin OTP, or after any mishaps via a superadmin password, or with a separate policy that blesses the current PCRs as golden. Such a policy could be used for sealing an NV index, or it could be set on local storage keys encrypted to the TPM's EKpub via `sbin/tpm2-send`, allowing for unattended server booting post-attestation, or attended server booting post-mishap (if the encrypted assets get stored "in the clear").
This is a sketch of how to represent and implement policies expressed in JSON using "take 2" as a model. Policies are represented as JSON objects that have: - zero, one, or more named policy parameters, which have type information - zero, one, or more bindings for a policy's parameters -- these can be default values, or values for parameters of other policies referred to by this one - an actual policy AST A policy can refer to other policies. This is especially necessary for TPM2_PolicyAuthorize() and TPM2_PolicyAuthorizeNV(), where the referred-to policy may not be known until run-time, so we really have to be able to separate the referrent and the referred-to policies. This may also be useful for TPM2_PolicyOr() even though its alternatives are static -- it may help organize policies, and to DRY. We treat TPM2_PolicyOr() as AST interior nodes. Interior nodes have to be singular TPM2_PolicyOr() commands. Leaf nodes are sequences of commands the first of which is allowed to be a hole, like TPM2_PolicyAuthorize() or TPM2_PolicyAuthorizeNV(). See ./policy.jq!
9163920
to
3f86e49
Compare
Let's try a different approach to expressing complex policies:
Policies as restricted bash scripts...
...that can do very little besides evaluate TPM policies, and which policy scripts are invoked via...
...a driver script,
sbin/tpm2-policy
, that sets up the environment for running the policy, and takes optional additional artifacts to make available to the policy, then runs it via/bin/rbash
.Policy script would run in the following restricted environment:
a temp dir as the current directory, with
$TMPDIR
set to$PWD
and in which all the necessary artifacts, including the policy script itself, shall have been placedvarious TPM2_POLICY... env vars, mainly TPM2_POLICY_SESSION (naming a saved TPM authorization context file)
$PATH
set to have just one element: anrbin
(see below).Artifacts can be supplied by the caller of
sbin/tpm2-policy
, or they can be embedded in the policy script as here documents, which can be extracted into the current directory (without clobbering any files) via therbin/writeartifact
program.All artifacts end up being files in
.
.There are two types of artifacts:
"constant artifacts" that are either embedded in the script or provided along with the script and named via the
-F
/--file
argument tosbin/tpm2-policy
:loadexternal
ed for use withpolicysigned
andpolicyauthorize
policyticket
and suchimport
ing andload
ingpolicyRef
valuesdynamic artifacts that are constructed while the policy is running, such as:
saved object context files for signer keys for
policysigned
andpolicyauthorize
tickets from
verifysignature
,policysecret
, andpolicysigned
timeout files
etc.
The "rbin" directory in the PATH for the execution of policy scripts, with:
tpm2_policy...
commandstpm2_policyor
is a bit special, naturallytpm2
,tpm2_import
,tpm2_loadexternal
andtpm2_verifysignature
, and possibly otherswriteartifact
-- a wrapper aroundxxd
andcat
for creating files from stdin so that artifacts can be embedded as here documents in the scriptThis way policies get all the expressive power of bash, and access to all the functionality of tpm2-tools' policy commands.
TBD:
Test, debug, test, ...
Maybe allow execution of
sbin/tpm2-recv
by wrapping it in the rbin?Add sample policies that are interesting, like using a combination of
policysigned
andpolicyauthorize
andcurl
(outside the policy script) to execute an external script that varies at runtime, or policies that use different passwords for N different users, or which usepolicysigned
to let some other entity authenticate N different users (usingpolicyRef
to name them, say), policies requiring golden PCRs OR external policy, etc. Showcasepolicyor
!It'd be very nice to be able to have a policy like this:
Perhaps with multiple superadmin authValues via
policyor
.One possible and interesting policy would be to use
policyauthorize
to allow a policy to be pluggable, but to have the signer only sign policy plugins that containpolicysigned
w/nonceTpm
. This is interesting becauseTPM2_PolicyAuthorize()
does not provide any way to expire or revoke signatures, butTPM2_PolicySigned()
does have a way to strongly bind a signature to a particular session (vianonceTpm
inclusion in the hash extended into thepolicyDigest
), and also a way to expire the signature (via time relative to the start of the session).Use of keys
TPM2_Duplicate()
ed to the TPM to deliverauthValues
as passwords for different users also seems interesting.Such a policy would allow a laptop to boot normally with a user password, and after emergency updates boot with an admin OTP, or after any mishaps via a superadmin password, or with a separate policy that blesses the current PCRs as golden.
Such a policy could be used for sealing an NV index, or it could be set on local storage keys encrypted to the TPM's EKpub via
sbin/tpm2-send
, allowing for unattended server booting post-attestation, or attended server booting post-mishap (if the encrypted assets get stored "in the clear").